#include "stdafx.h"
#include "CppUnitTest.h"

#include <HSModel/Model3D.h>
#include <HSModel/ObjParser.h>
#include <HSModel/GeometryUtils.h>

#include <functional>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace HSModelTests
{
	TEST_CLASS(ObjParserTests)
	{
	public:
		
		TEST_METHOD(ObjParserShouldTBeFalseWhenFileNotFound)
		{
			Model3D expectation;
			auto flag=ImportObj(expectation, L"asdasd");
			Assert::IsFalse(flag);
		}

		TEST_METHOD(ObjParserShouldTBeFalseWhenFileIsEmpty)
		{
			Model3D expectation;
			bool flag=ImportObj(expectation, L"..//..//TestData/Empty.obj");
			Assert::IsFalse(flag);
		}

		TEST_METHOD(ObjParserShouldTBeFalseWhenContentIsBad)
		{
			Model3D expectation;
			bool flag=ImportObj(expectation, L"..//..//TestData/diamond.obj");
			Assert::IsFalse(flag);
		}

		TEST_METHOD(ObjParserShouldTBuildCubeWhenCubeObj)
		{
			Model3D expectation;
			bool flag;
			flag=ImportObj(expectation, L"..//..//TestData/Cube.obj");
			Assert::IsTrue(flag);
			Model3D::TrianglesIteratorConstGetter iter_getter=expectation.Triangles();
			Model3D::Triangle3DIteratorConst iter=iter_getter.begin();
			iter++;
			TVector3 triangle1p1=(*iter).GetPoint(0);
			TVector3 triangle1p2=(*iter).GetPoint(1);
			TVector3 triangle1p3=(*iter).GetPoint(2);
			
			//first triangle
			Assert::AreEqual(0.0, triangle1p1[0]);
			Assert::AreEqual(0.0, triangle1p1[1]);
			Assert::AreEqual(0.0, triangle1p1[2]);
			Assert::AreEqual(0.0, triangle1p2[0]);
			Assert::AreEqual(0.0, triangle1p2[1]);
			Assert::AreEqual(1.0, triangle1p2[2]);
			Assert::AreEqual(1.0, triangle1p3[0]);
			Assert::AreEqual(0.0, triangle1p3[1]);
			Assert::AreEqual(1.0, triangle1p3[2]);	

			for(int i=1;i<8;i++)
				iter++;
			TVector3 triangle2p1=(*iter).GetPoint(0);
			TVector3 triangle2p2=(*iter).GetPoint(1);
			TVector3 triangle2p3=(*iter).GetPoint(2);
			
			//second triangle
			Assert::AreEqual(0.0, triangle2p1[0]);
			Assert::AreEqual(0.0, triangle2p1[1]);
			Assert::AreEqual(0.0, triangle2p1[2]);
			Assert::AreEqual(1.0, triangle2p2[0]);
			Assert::AreEqual(0.0, triangle2p2[1]);
			Assert::AreEqual(0.0, triangle2p2[2]);
			Assert::AreEqual(1.0, triangle2p3[0]);
			Assert::AreEqual(1.0, triangle2p3[1]);
			Assert::AreEqual(0.0, triangle2p3[2]);

		}

		TEST_METHOD(ObjParserShouldBeFalseWhenContentWithoutFigures)
		{
			Model3D expectation;
			bool flag;
			flag=ImportObj(expectation, L"..//..//TestData/Cube2.obj");
			Assert::IsFalse(flag);
		}

		TEST_METHOD(ObjParserShouldTBuildCubeWhenCube3Obj)
		{
			Model3D expectation;
			bool flag;
			flag=ImportObj(expectation, L"..//..//TestData/Cube3.obj");
			Assert::IsTrue(flag);
			Model3D::TrianglesIteratorConstGetter iter_getter=expectation.Triangles();
			Model3D::Triangle3DIteratorConst iter=iter_getter.begin();
			iter++;
			TVector3 triangle1p1=(*iter).GetPoint(0);
			TVector3 triangle1p2=(*iter).GetPoint(1);
			TVector3 triangle1p3=(*iter).GetPoint(2);
			
			//first triangle
			Assert::AreEqual(0.0, triangle1p1[0]);
			Assert::AreEqual(0.0, triangle1p1[1]);
			Assert::AreEqual(0.0, triangle1p1[2]);
			Assert::AreEqual(0.0, triangle1p2[0]);
			Assert::AreEqual(0.0, triangle1p2[1]);
			Assert::AreEqual(1.0, triangle1p2[2]);
			Assert::AreEqual(1.0, triangle1p3[0]);
			Assert::AreEqual(0.0, triangle1p3[1]);
			Assert::AreEqual(1.0, triangle1p3[2]);	

			for(int i=1;i<8;i++)
				iter++;
			TVector3 triangle2p1=(*iter).GetPoint(0);
			TVector3 triangle2p2=(*iter).GetPoint(1);
			TVector3 triangle2p3=(*iter).GetPoint(2);
			
			//second triangle
			Assert::AreEqual(0.0, triangle2p1[0]);
			Assert::AreEqual(0.0, triangle2p1[1]);
			Assert::AreEqual(0.0, triangle2p1[2]);
			Assert::AreEqual(1.0, triangle2p2[0]);
			Assert::AreEqual(0.0, triangle2p2[1]);
			Assert::AreEqual(0.0, triangle2p2[2]);
			Assert::AreEqual(1.0, triangle2p3[0]);
			Assert::AreEqual(1.0, triangle2p3[1]);
			Assert::AreEqual(0.0, triangle2p3[2]);

		}

		TEST_METHOD(ObjParserShouldBeFalseWhenplants3Obj)
		{
			Model3D expectation;
			bool flag;
			flag=ImportObj(expectation, L"..//..//TestData/plants3.obj");
			Assert::IsFalse(flag);
		}
	
		TEST_METHOD(ObjParserShouldBeFalseWhenPalmObj)
		{
			Model3D expectation;
			bool flag;
			flag=ImportObj(expectation, L"..//..//TestData/Palm.obj");
			Assert::IsFalse(flag);
		}

		TEST_METHOD(ObjParserShouldBuildCorrectWhen5vertexesObj)
		{
			Model3D expectation;
			bool flag;
			flag=ImportObj(expectation, L"..//..//TestData/5vertexes.obj");
			Assert::IsTrue(flag);
			Model3D::TrianglesIteratorConstGetter iter_getter=expectation.Triangles();
			Model3D::Triangle3DIteratorConst iter=iter_getter.begin();
			iter++;
			iter++;
			TVector3 triangle1p1=(*iter).GetPoint(0);
			TVector3 triangle1p2=(*iter).GetPoint(1);
			TVector3 triangle1p3=(*iter).GetPoint(2);
			Assert::AreEqual(0.0, triangle1p1[0]);
			Assert::AreEqual(0.0, triangle1p1[1]);
			Assert::AreEqual(0.0, triangle1p1[2]);
			Assert::AreEqual(0.8, triangle1p2[0]);
			Assert::AreEqual(0.3, triangle1p2[1]);
			Assert::AreEqual(1.1, triangle1p2[2]);
			Assert::AreEqual(0.6, triangle1p3[0]);
			Assert::AreEqual(0.3, triangle1p3[1]);
			Assert::AreEqual(0.7, triangle1p3[2]);
		}

    TEST_METHOD(ObjParserShouldLoadTexturedCube)
      {
      Model3D expectation;

      Assert::IsTrue(ImportObj(expectation, L"..//..//TestData/Cube3.obj"));
      Model3D::TrianglesIteratorConstGetter iter_getter = expectation.Triangles();
      Model3D::Triangle3DIteratorConst iter = iter_getter.begin();

      for(int i = 0; i < 5; i++) // 6th: f  3/1  4/1  8/1 
        iter++;

      Assert::AreEqual(0.5, iter->GetPointUV(0).X());
      Assert::AreEqual(0.4, iter->GetPointUV(1).Y());

      for(int i = 0; i < 3; i++) // 9th: f  1/1/4  5/1/4  6/1/4 
        iter++;

      Assert::AreEqual(0.5, iter->GetPointUV(0).X());
      Assert::AreEqual(0.4, iter->GetPointUV(1).Y());
      }
		TEST_METHOD(ObjParserShouldLoadNormalsInCube)
			{
			Model3D expectation;

			Assert::IsTrue(ImportObj(expectation, L"..//..//TestData/Cube3.obj"));
			Model3D::TrianglesIteratorConstGetter iter_getter = expectation.Triangles();
      Model3D::Triangle3DIteratorConst iter = iter_getter.begin();

			 for(int i = 0; i < 6; i++) // 7th: f 5//5  7//5  8//5       where vn  1.0  0.0  0.0
				 iter++;
			 Assert::AreEqual(1.0, iter->GetPointNormal(0).X());
			 Assert::AreEqual(0.0, iter->GetPointNormal(0).Y());
			 Assert::AreEqual(0.0, iter->GetPointNormal(0).Z());
			 Assert::AreEqual(1.0, iter->GetPointNormal(1).X());
			 Assert::AreEqual(0.0, iter->GetPointNormal(1).Y());
			 Assert::AreEqual(0.0, iter->GetPointNormal(1).Z());
			 Assert::AreEqual(1.0, iter->GetPointNormal(2).X());
			 Assert::AreEqual(0.0, iter->GetPointNormal(2).Y());
			 Assert::AreEqual(0.0, iter->GetPointNormal(2).Z());
			}
	};
}